﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Localization;
using Volo.Abp.ObjectExtending;
using Volo.Abp.SettingManagement;
using YunxSoft.Abp.LanguageManagement.Permissions;

namespace YunxSoft.Abp.LanguageManagement;

[Authorize(LanguageManagementPermissions.Languages.Default)]
public class LanguageAppService : LanguageManagementAppService, ILanguageAppService
{
    protected ISettingManager SettingManager { get; }

    protected ILanguageRepository LanguageRepository { get; }

    protected AbpLocalizationOptions AbpLocalizationOptions { get; }

    public LanguageAppService(ISettingManager settingManager, IOptions<AbpLocalizationOptions> abpLocalizationOptions,
        ILanguageRepository languageRepository)
    {
        SettingManager = settingManager;
        LanguageRepository = languageRepository;
        AbpLocalizationOptions = abpLocalizationOptions.Value;
    }

    public virtual async Task<ListResultDto<LanguageDto>> GetAllListAsync()
    {
        var languages = await LanguageRepository.GetListAsync(true);
        var defaultLanguage = await FindDefaultLanguage(languages);
        var list = ObjectMapper.Map<List<Language>, List<LanguageDto>>(languages);
        if (defaultLanguage != null)
        {
            var languageDto = list.Find(l =>
                l.CultureName == defaultLanguage.CultureName && l.UiCultureName == defaultLanguage.CultureName);
            if (languageDto != null)
            {
                languageDto.IsDefaultLanguage = true;
            }
        }
        return new ListResultDto<LanguageDto>(list);
    }
    
    
    public virtual async Task<PagedResultDto<LanguageDto>> GetListAsync(GetLanguagesInput input)
    {
        var count = await LanguageRepository.GetCountAsync(input.Filter);
        var languages =
            await LanguageRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter);
        var defaultLanguage = await FindDefaultLanguage(languages);
        var list = ObjectMapper.Map<List<Language>, List<LanguageDto>>(languages);
        if (defaultLanguage != null)
        {
            var languageDto = list.Find(l =>
                l.CultureName == defaultLanguage.CultureName && l.UiCultureName == defaultLanguage.CultureName);
            if (languageDto != null)
            {
                languageDto.IsDefaultLanguage = true;
            }
        }

        return new PagedResultDto<LanguageDto>(count, list);
    }

    public virtual async Task<LanguageDto> GetAsync(Guid id)
    {
        var result = await LanguageRepository.GetAsync(id);
        var languageDto = ObjectMapper.Map<Language, LanguageDto>(result);
        languageDto.IsDefaultLanguage = await FindDefaultLanguage(new List<Language> {result}) != null;
        return languageDto;
    }

    [Authorize(LanguageManagementPermissions.Languages.Create)]
    public virtual async Task<LanguageDto> CreateAsync(CreateLanguageDto input)
    {
        var language = new Language(base.GuidGenerator.Create(), input.CultureName, input.UiCultureName,
            input.DisplayName, input.FlagIcon, input.IsEnabled);
        input.MapExtraPropertiesTo(language);
        language = await LanguageRepository.InsertAsync(language);
        return base.ObjectMapper.Map<Language, LanguageDto>(language);
    }

    [Authorize(LanguageManagementPermissions.Languages.Update)]
    public virtual async Task<LanguageDto> UpdateAsync(Guid id, UpdateLanguageDto input)
    {
        var language = await LanguageRepository.GetAsync(id);
        language.SetDisplayName(input.DisplayName);
        language.FlagIcon = input.FlagIcon;
        language.IsEnabled = input.IsEnabled;
        input.MapExtraPropertiesTo(language);
        await LanguageRepository.UpdateAsync(language);
        return ObjectMapper.Map<Language, LanguageDto>(language);
    }

    [Authorize(LanguageManagementPermissions.Languages.Delete)]
    public virtual async Task DeleteAsync(Guid id)
    {
        await LanguageRepository.DeleteAsync(id);
    }

    [Authorize(LanguageManagementPermissions.Languages.ChangeDefault)]
    public virtual async Task SetAsDefaultAsync(Guid id)
    {
        var result = await LanguageRepository.GetAsync(id);
        await SettingManager.SetForCurrentTenantAsync("Abp.Localization.DefaultLanguage",
            result.CultureName + ";" + result.UiCultureName, false);
    }

    public virtual Task<List<LanguageResourceDto>> GetResourcesAsync()
    {
        return Task.FromResult((from r in AbpLocalizationOptions.Resources.Values
            select new LanguageResourceDto
            {
                Name = r.ResourceName
            }).ToList());
    }

    public virtual async Task<List<CultureInfoDto>> GetCultureListAsync()
    {
        return await Task.FromResult((from c in CultureInfo.GetCultures(CultureTypes.AllCultures)
            where !string.IsNullOrEmpty(c.Name)
            select new CultureInfoDto
            {
                DisplayName = c.DisplayName,
                Name = c.Name
            }).ToList());
    }

    protected virtual async Task<Language> FindDefaultLanguage(List<Language> languages)
    {
        string text = await SettingManager.GetOrNullForCurrentTenantAsync("Abp.Localization.DefaultLanguage");
        Language result;
        if (text.IsNullOrEmpty())
        {
            result = null;
        }
        else
        {
            ValueTuple<string, string> valueTuple = LocalizationSettingHelper.ParseLanguageSetting(text);
            string item = valueTuple.Item1;
            string item2 = valueTuple.Item2;
            result = languages.FindByCulture(item, item2);
        }

        return result;
    }
}